'''
Created on 2010/08/11

@author: yukiyonezawa
'''
from pyrfid.Util.Util import Util
import binascii
from pyrfid.DataProtocol.DSFID.AccessMethod.PackedObjects.CharacterSet import CharacterSet
from pyrfid.asn1.Encoder import Encoder
from pyrfid.DataProtocol.DSFID.Processor.Decompactor import Decompactor
import sys
from django.conf.urls.defaults import include
import re
from pyrfid.DataProtocol.DSFID.AccessMethod.PackedObjects.IDInfo import IDInfo
from pyrfid.DataProtocol.LogicalMemory.DataSet import DataSet
from pyrfid.DataProtocol.AddObject import AddObject

class Data(object):
    
    AN_HEADER_HEADER = "header"
    AN_HEADER_PREFIX = "prefix"
    AN_HEADER_SUFFIX = "suffix"
    AN_HEADER_MAP = "map"
    
    AN_BINARY_NUMERIC_BINARY = "numeric_binary"
    AN_BINARY_NON_NUMERIC_BINARY = "non_numeric_binary"
    AN_BINARY_BASE_10_BINARY = "base_10_binary"
    AN_BINARY_NON_NUMERIC_BINARY = "non_numeric_binary"
    AN_BINARY_PADBITS = "padbits"
    
    __AN_HEADER_BASE30 = "0"
    __AN_HEADER_BASE74 = "10"
    __AN_HEADER_BASE256 = "11"
    
    KNOWN_LENGTH_NUMERIC = list()
    AN_HEADER = {AN_HEADER_HEADER:"0", AN_HEADER_PREFIX:"0", AN_HEADER_SUFFIX:"0", AN_HEADER_MAP:""}
    AN_BINARY = {AN_BINARY_NUMERIC_BINARY:"", AN_BINARY_NON_NUMERIC_BINARY:"", AN_BINARY_BASE_10_BINARY:"", AN_BINARY_NUMERIC_BINARY:"", AN_BINARY_PADBITS:""}
    
    def __init__(self):
        self.AN_HEADER = {self.AN_HEADER_HEADER:"0", self.AN_HEADER_PREFIX:"0", self.AN_HEADER_SUFFIX:"0", self.AN_HEADER_MAP:""}
        self.AN_BINARY = {self.AN_BINARY_NUMERIC_BINARY:"", self.AN_BINARY_NON_NUMERIC_BINARY:"", self.AN_BINARY_BASE_10_BINARY:"", self.AN_BINARY_NUMERIC_BINARY:"", self.AN_BINARY_PADBITS:""}
    
    def build(self, defined_packed_objects, changed_order_add_data_set_list):
        #separate numeric and alpha_numeric
        for data_set in changed_order_add_data_set_list:            
            for idInfo in defined_packed_objects.getIDInfo():
                
                is_included = False
                for oid in idInfo.getOIDString():                                        
                    if data_set.OBJECT_IDENTIFIER == Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + oid):
                        is_included = True
                        break
                
                if is_included == False:
                    continue
                
                if "an" in idInfo.getFormatStr():
                    self.__encodeAlphaNumeric(data_set.OBJECT)
                else:   
                    self.__encodeNumeric(data_set.OBJECT, idInfo.getFormatStr())                
                break
        
    
    def setPadBit(self, length):
        self.AN_BINARY[Data.AN_BINARY_PADBITS] = "0" * length
            
    def getBit(self):
        
        return_bit = ""
        
        for known_numeric in self.KNOWN_LENGTH_NUMERIC:
            return_bit += known_numeric
        
        #AN_HEADER
        return_bit += self.AN_HEADER[Data.AN_HEADER_HEADER]
        return_bit += self.AN_HEADER[Data.AN_HEADER_PREFIX]
        return_bit += self.AN_HEADER[Data.AN_HEADER_SUFFIX]
        return_bit += self.AN_HEADER[Data.AN_HEADER_MAP]
                
        #AN_BINARY        
        return_bit += self.AN_BINARY[Data.AN_BINARY_NUMERIC_BINARY]
        return_bit += self.AN_BINARY[Data.AN_BINARY_NON_NUMERIC_BINARY]
        return_bit += self.AN_BINARY[Data.AN_BINARY_BASE_10_BINARY]
        return_bit += self.AN_BINARY[Data.AN_BINARY_PADBITS]
        
        
        return return_bit
    
    @classmethod
    def analyzeData(cls, all_data_bit, secondary, auxformat, included_idInfo, defined_packed_objects):
        data = Data()
        
        #check numeric or alphanumeric & length
        numeric_list = list()
        alphanumeric_list = list()
        variable_index = 0
        #the order of included_idInfo is defined.
        for idInfo in included_idInfo:  
            if idInfo.isCombinationOID() == True:
                #(A)(B)(C)                
                for index, splited_format in enumerate(idInfo.getSplitedFormatStr()):
                    #A, B, C
                    #alphanumeric
                    if "an" in splited_format:
                        if "*" in splited_format:
                            alphanumeric_list.append({"oid":idInfo.getSplitedOIDStringByIndex(index), "format":splited_format, "variable_index":variable_index})
                            variable_index += 1
                        else:
                            alphanumeric_list.append({"oid":idInfo.getSplitedOIDStringByIndex(index),"format":splited_format, "variable_index":""})
                    else:
                        if "*" in splited_format:
                            numeric_list.append({"oid":idInfo.getSplitedOIDStringByIndex(index),"format":splited_format, "variable_index":variable_index})
                            variable_index += 1
                        else:
                            numeric_list.append({"oid":idInfo.getSplitedOIDStringByIndex(index),"format":splited_format, "variable_index":""})
            else:
                if "an" in idInfo.getFormatStr():
                    if "*" in splited_format:
                        alphanumeric_list.append({"oid":idInfo.getOIDString(),"format":idInfo.getFormatStr(), "variable_index":variable_index})
                        variable_index += 1
                    else:
                        alphanumeric_list.append({"oid":idInfo.getOIDString(),"format":idInfo.getFormatStr(),"variable_index":""})
                else:
                    if "*" in splited_format:
                        numeric_list.append({"oid":idInfo.getOIDString(),"format":idInfo.getFormatStr(), "variable_index":variable_index})
                        variable_index += 1
                    else:
                        numeric_list.append({"oid":idInfo.getOIDString(),"format":idInfo.getFormatStr(),"variable_index":""})
                
        all_data_bit, added_objects, secondary_index = data.analyzeNumeric(all_data_bit, secondary, auxformat, included_idInfo, defined_packed_objects, numeric_list)
        
        added_objects = data.analyzeAlphaNumeric(all_data_bit, secondary, auxformat, included_idInfo, defined_packed_objects, alphanumeric_list, secondary_index, added_objects)
        
        return added_objects
        
    def analyzeNumeric(self, all_data_bit, secondary, auxformat, included_idInfo, defined_packed_objects, numeric_list):
        
        added_objects = list()
        secondary_index = 0
        for numeric in numeric_list:
            ################################################################################
            # calculate object identifier
            object_identifier = ""
            if type(numeric["oid"]) == type([]):
                #need secondary info
                secondary_id = secondary.getSecondaryIdByIndex(secondary_index)
                secondary_index += 1
                object_identifier = Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + secondary_id["PREFIX"] + secondary_id["SECONDARY"])
            else:
                object_identifier = Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + numeric["oid"])
            ################################################################################                                
            
            ################################################################################
            # calculate value
            object_length = 0
            fix_value_str = "" 
            for format_value in numeric['format']:
                if format_value.isdigit() == True:
                    fix_value_str += format_value
                else:
                    break
            object_length = int(fix_value_str) 
            if numeric['variable_index'] != "":
            #for variable-length
                object_length += auxformat.getVariableLength(numeric['variable_index'])            
            max_value = 0
            for index in range(object_length):
                max_value += 10**index * 9            
            bit_max_lengthe = len(Util.convertIntToBit(max_value))
            object_value = Encoder.octetStrEncode( str(int(all_data_bit[:bit_max_lengthe], 2)).rjust(object_length, "0") )
            all_data_bit = all_data_bit[bit_max_lengthe:]
            print all_data_bit
            ################################################################################
            added_objects.append(AddObject(object_identifier, "", object_value, auxformat.getCompactionTypeInApplication(), ""))
        
        return all_data_bit, added_objects, secondary_index
    
    def analyzeAlphaNumeric(self, all_data_bit, secondary, auxformat,included_idInfo, defined_packed_objects, alphanumeric_list, secondary_index, added_objects):
        
        #analyze ANHeader
        #__AN_HEADER_BASE***
        an_header = all_data_bit[0]
        #check ENCODE BASE_30 or BASE_***
        if an_header != self.__AN_HEADER_BASE30:
            an_header +=  all_data_bit[1]
        all_data_bit = all_data_bit[len(an_header):]
        
        #analyze ANPrefix
        an_prefix = all_data_bit[0]
        all_data_bit = all_data_bit[len(an_prefix):]
        
        #analyze ANSuffix
        an_suffix = all_data_bit[0]
        all_data_bit = all_data_bit[len(an_suffix):]
        
        character_map_list = list()
        #############################################################################
        #calculate character map
        for alphanumeric in alphanumeric_list:   
            ################################################################################
            # calculate length
            object_length = 0
            fix_value_str = "" 
            for format_value in alphanumeric['format']:
                if format_value.isdigit() == True:
                    fix_value_str += format_value
                else:
                    break
            object_length = int(fix_value_str) 
            if alphanumeric['variable_index'] != "":
            #for variable-length
                object_length += auxformat.getVariableLength(alphanumeric['variable_index'])                
            character_map_list.append(all_data_bit[:object_length - 1])
            all_data_bit = all_data_bit[object_length - 1:]
            ################################################################################
                
        numeric_count = 0
        alpha_count = 0

        for character_map in character_map_list:
            for character in character_map:
                if character == "0":
                    numeric_count += 1
                else:
                    alpha_count += 1
        max_value = 0
        for index in range(numeric_count):
            max_value += 10** index * 9  
        bit_max_lengthe = len(Util.convertIntToBit(max_value))        
        #n_digit_value
        numeric_bit = all_data_bit[:bit_max_lengthe]        
        print numeric_bit
        
        
        all_data_bit = all_data_bit[bit_max_lengthe:]
        #check BASE_***
        max_value = 0
        for index in range(alpha_count):
            max_value = 30 ** index * CharacterSet.getValByCharFromBASE30("Z")                
        bit_max_lengthe = len(Util.convertIntToBit(max_value))        
        alpha_bit = all_data_bit[:bit_max_lengthe]
        
        print alpha_bit
        
        numeric_str = str( int(numeric_bit, 2) )
        alpha_int = int(alpha_bit, 2)
        alpha_caluculate_index = 0
        remaining_value_list = list()
        
        while True:
            remaining_value_list.append(alpha_int % 30)
            alpha_int = alpha_int / 30
            if alpha_int == 0:
                break
            alpha_caluculate_index += 1        
                
        reversed_val = remaining_value_list[::-1]
        characters_str = ""
        
        for val in reversed_val:
            characters_str += CharacterSet.getCharByValFormBASE30(val)
        
        numeric_index = 0
        character_index = 0
        alphanumeric_value_list = list()
        for character_map in character_map_list:            
            temp_character = ""
            for character in character_map:
                if character == "0":
                    temp_character += numeric_str[numeric_index]
                    numeric_index += 1
                else:
                    temp_character += characters_str[character_index]
                    character_index += 1
            alphanumeric_value_list.append(temp_character)
        
        
        for index, alphanumeric in enumerate(alphanumeric_list):
            ################################################################################
            # calculate object identifier
            object_identifier = ""
            if type(alphanumeric["oid"]) == type([]):
                #need secondary info
                secondary_id = secondary.getSecondaryIdByIndex(secondary_index)
                secondary_index += 1
                object_identifier = Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + secondary_id["PREFIX"] + secondary_id["SECONDARY"])
            else:
                object_identifier = Encoder.oidEncode(defined_packed_objects.getKRootOID() + " " + alphanumeric["oid"])
            ################################################################################                                
            object_value =  Encoder.octetStrEncode( alphanumeric_value_list[index] )
            ################################################################################
            added_objects.append(AddObject(object_identifier, "", object_value, auxformat.getCompactionTypeInApplication(), ""))
        
        return added_objects
        
    def __encodeNumeric(self, value, format_string):
        #format_string 6n means that the max numeric is 999999 which is hex 0001 1000 0110 1001 1111                
        #first length check
        length = format_string.split("n")[0]
        max_value = 0
        for index in range(int(length)):
            max_value += 10 ** index * 9        
        bit_max_lengthe = len(Util.convertIntToBit(max_value))
        
        self.KNOWN_LENGTH_NUMERIC.append(Util.convertIntToBit(int(value), bit_max_lengthe))
        print self.KNOWN_LENGTH_NUMERIC
        
    def __encodeAlphaNumeric(self, value):
        #create map
        alpha_numeric_map = ""
        numeric_str = ""
        alpha_str = ""
        for check_value in value:
            if check_value.isdigit() == True:
                alpha_numeric_map += "0"
                numeric_str += check_value
            else:
                alpha_numeric_map += "1"
                alpha_str += check_value        
        
        self.AN_HEADER[Data.AN_HEADER_MAP] = alpha_numeric_map
        
        max_value = 0
        for index in range(len(numeric_str)):
            max_value += 10**index * 9  
        bit_max_lengthe = len(Util.convertIntToBit(max_value))        
        self.AN_BINARY[Data.AN_BINARY_NUMERIC_BINARY] =  Util.convertIntToBit(int(numeric_str), bit_max_lengthe)
        
        max_value = 0
        current_value = 0
        for index in range(len(alpha_str)):
            max_value = 30 ** index * CharacterSet.getValByCharFromBASE30("Z")
            current_value += 30 ** (len(alpha_str) - index - 1) * CharacterSet.getValByCharFromBASE30(alpha_str[index])
        bit_max_lengthe = len(Util.convertIntToBit(max_value))
        self.AN_BINARY[Data.AN_BINARY_NON_NUMERIC_BINARY] =  Util.convertIntToBit(current_value, bit_max_lengthe)
        
if __name__ == '__main__':
    hoga = Data("", "")